/*
 * Copyright (c) 2016 Qualcomm Technologies, Inc.
 * All Rights Reserved.
 * Qualcomm Technologies, Inc. Confidential and Proprietary.
 */
package com.thunder.rebot.rebotclient.vam.ui;

import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.thunder.rebot.rebotclient.R;
import com.thunder.rebot.rebotclient.vam.Algo;
import com.thunder.rebot.rebotclient.vam.entity.FaceFrame;
import com.thunder.rebot.rebotclient.vam.entity.MapperParams;
import com.thunder.rebot.rebotclient.vam.utils.Utils;

import java.util.ArrayList;

/**
 * Class for fd frames
 */

public class FdFramesUI implements View.OnTouchListener {
    private static final String TAG = FdFramesUI.class.getSimpleName();

    /**
     * Interface for the guide listeners
     */
    public interface EnrollFrameUIListener {
        /**
         * Notification on picture ready or not ready
         *
         * @param ready true if ready, false otherwise
         */
        void onPictureReady(boolean ready);

        /**
         * Notification on picture best fit status
         *
         * @param bestFit true if best fit, false otherwise
         */
        void onPictureBestFit(boolean bestFit);
    }

    private static final float MIN_FACE_OVERLAP = 0.9f;
    private static final float MIN_WIDTH_RATIO = 0.6f;

    private enum ViewType {
        NONE, FACE_ALL, FACE_SELECTED
    }

    private ViewType viewType = ViewType.NONE;
    private ArrayList<FaceFrame> frames = new ArrayList<FaceFrame>();
    private FaceFrame selectedFrame = null;

    private EnrollFrameUIListener listener = null;
    private final Drawable drawable;
    private final Paint activeFramePaint;
    private final Paint[] inactiveFramePaints = new Paint[Utils.MAX_ABSENCE];

    private RectF roi = new RectF();
    private boolean activeTemplate = false;
    private final Algo.FaceMatcher matcher;

    /**
     * Constructor for the class
     *
     * @param resources activity resources
     * @param drawable  parent drawable
     * @param matcher   face matcher
     */
    /* package */ FdFramesUI(Resources resources, Drawable drawable, Algo.FaceMatcher matcher) {
        this.drawable = drawable;
        this.matcher = matcher;

        float frameStroke =  resources.getDimension(R.dimen.cam_data_frame_stroke);
        int activeFrameColor = resources.getColor(R.color.cam_data_active_frame);
        int inactiveFrameColor = resources.getColor(R.color.cam_data_inactive_frame);

        activeFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        activeFramePaint.setStyle(Paint.Style.STROKE);
        activeFramePaint.setColor(activeFrameColor);
        activeFramePaint.setStrokeWidth(frameStroke);

        int alpha = 0xff / inactiveFramePaints.length;
        for (int i = 0; i < inactiveFramePaints.length; i++) {
            inactiveFramePaints[i] = new Paint(Paint.ANTI_ALIAS_FLAG);
            inactiveFramePaints[i].setStyle(Paint.Style.STROKE);
            inactiveFramePaints[i].setColor(inactiveFrameColor);
            inactiveFramePaints[i].setAlpha(0xff - alpha * i);
            // Log.d(TAG, "Setting alpha:" + (int) (0xff - alpha * i));
            inactiveFramePaints[i].setStrokeWidth(frameStroke);
        }
        reset();
    }

    /**
     * Sets the listener for the enroll frame UI events
     *
     * @param l listener
     */
    public void setListener(EnrollFrameUIListener l) {
        this.listener = l;
    }

    /**
     * resets the frames
     */
    public void reset() {
        // Log.d(TAG, "Reset called");
        frames.clear();
        resetSelection();
    }

    /**
     * method to reset the selection
     */
    /* package */ void resetSelection() {
        selectedFrame = null;
        viewType = ViewType.FACE_ALL;
    }

    /**
     * method to draw the enroll frames
     *
     * @param canvas canvas
     */
    /* package */ void draw(Canvas canvas) {
        if (viewType == ViewType.FACE_ALL) {
            for (FaceFrame frame : frames) {
                int count = frame.getAbsence();
                canvas.drawRect(frame.getRect(), inactiveFramePaints[count - 1]);
            }
        } else if (selectedFrame != null) {
            canvas.drawRect(selectedFrame.getRect(), activeFramePaint);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
            if (selectedFrame == null) {
                FaceFrame clickedFrame = null;
                for (FaceFrame frame : frames) {
                    if (Algo.isPointInside(frame.getRect(), event.getX(), event.getY(), 0)) {
                        clickedFrame = frame;
                        break;
                    }
                }
                if (clickedFrame != null) {
                    selectedFrame = clickedFrame;
                    viewType = ViewType.FACE_SELECTED;
                    frames.clear();

                    if (listener != null) {
                        listener.onPictureReady(true);
                    }
                    updateGuideBmp();
                    drawable.invalidateSelf();
                }
            } else {
                selectedFrame = null;
                viewType = ViewType.FACE_ALL;
                if (listener != null) {
                    listener.onPictureReady(false);
                }
            }
        }

        return true;
    }

    private void updateGuideBmp() {
        float overlapped = Algo.getOverlapping(roi, selectedFrame.getRect());

        boolean matched = false;
        if (overlapped >= MIN_FACE_OVERLAP) {
            float widthRatio = selectedFrame.getRect().width() / roi.width();
            Log.d(TAG, "overlapped: " + overlapped + "," + widthRatio);
            if (widthRatio >= MIN_WIDTH_RATIO) {
                matched = true;
            }
        } else {
            Log.d(TAG, "overlap: " + overlapped);
        }

        if (matched != activeTemplate) {
            activeTemplate = matched;
            if (listener != null) {
                listener.onPictureBestFit(activeTemplate);
            }
        }
    }

    /**
     * Sets the ROI information
     *
     * @param bounds drawable visible region
     */
    /* package */ void setRoi(Rect bounds) {
        if (bounds.width() > bounds.height()) { // landscape
            roi.set((float) bounds.width() / 3, 0, ((float) bounds.width() * 2) / 3,
                    bounds.height());

        } else {
            roi.set((float) bounds.width() / 4, 0, ((float) bounds.width() * 3) / 4,
                    bounds.height());
        }
    }

    /**
     * sets the alpha for the frames UI
     *
     * @param alpha alpha value
     */
    /* package */ void setAlpha(int alpha) {
        activeFramePaint.setAlpha(alpha);
        for (Paint inactivePaint : inactiveFramePaints) {
            inactivePaint.setAlpha(alpha);
        }
    }

    /**
     * Method to set the color filter
     *
     * @param filter color filter
     */
    /* package */ void setColorFilter(ColorFilter filter) {
        activeFramePaint.setColorFilter(filter);
        for (Paint inactivePaint : inactiveFramePaints) {
            inactivePaint.setColorFilter(filter);
        }
    }

    /**
     * adds the fd frames
     *
     * @param imageFaceFrames image face frames
     * @param params          mapper params
     */
    /* package */ void addFrames(ArrayList<FaceFrame> imageFaceFrames, MapperParams params) {
        // change to screen frames
        //Log.d(TAG, "Got frames " + imageFaceFrames.size());
        ArrayList<FaceFrame> faceFrames = Utils.image2ScreenFaceFrames(imageFaceFrames, params);
        if (viewType == ViewType.FACE_ALL) {
            if (Algo.trackFaceFrames(frames, faceFrames, matcher)) {
                drawable.invalidateSelf();
            }
        } else if (viewType == ViewType.FACE_SELECTED && selectedFrame != null) {
            Log.e("Absence",selectedFrame.getAbsence()+"");
            if (Algo.trackFace(selectedFrame, faceFrames, matcher)) {
                updateGuideBmp();
                drawable.invalidateSelf();
            }
            if (selectedFrame.getAbsence() > Utils.MAX_ABSENCE) {
                viewType = ViewType.FACE_ALL;
                selectedFrame = null;

                if (listener != null) {
                    listener.onPictureReady(false);
                }

                drawable.invalidateSelf();
            }
        }
    }

    /**
     * method to get the mapped selcted rect
     *
     * @param imageFaceFrames image face frames
     * @param params          mapper params
     * @return matching rect
     */
    /* package */ RectF getMatchingSelectedRect(ArrayList<FaceFrame> imageFaceFrames, MapperParams params) {
        ArrayList<FaceFrame> faceFrames = Utils.image2ScreenFaceFrames(imageFaceFrames, params);
        int matchingIndex = Algo.getOverlappingRect(selectedFrame, faceFrames);
        FaceFrame faceFrame = (matchingIndex >= 0) ? imageFaceFrames.get(matchingIndex) : null;
        return (faceFrame == null)? null : faceFrame.getRect();
    }
    
    public RectF getSelectedRectf(){
        if(selectedFrame==null){
            return null;
        }
    	return selectedFrame.getRect();
    }
}
